/////////////////////////////////////////////////////////////////////////////
// Purpose:     File access management
// Author:      Jesus Gonzalez
// Modified by:
// Copyright:   (c) 2003-2013 Jesus Gonzalez <jgonzalez@gdr-sistemas.com>
// License:     BSD License
/////////////////////////////////////////////////////////////////////////////

#ifndef _SMARTLIB_FILE_H_
#define _SMARTLIB_FILE_H_

/**
 * \file
 * %File access management.
 */

#include <SmartLib/ExtendedTypes.h>
#include <SmartLib/SmartPtr.h>
#include <SmartLib/ByteArray.h>
#include <string>
#include <limits.h>

///@defgroup res_mgmt Resource management
///@{

/**
 * The File class is used to access files on the OS filesystem.
 */
class File : public SmartObject
{
public:
	DECLARE_SMARTPTR_NEWCTOR(File);

    /**
     * %File opening modes.
     */
    enum EMode
    {
        READ = 1,            /**< Opens the file in read mode */
        WRITE = 2,           /**< Opens the file in write mode */
        READ_WRITE = 3,      /**< Opens the file in read/write mode */
        WRITE_TRUNCATE = 4   /**< Opens the file in write mode, clearing the file contents */
    };

    /**
     * %File locking modes.
     */
    enum EOpts
    {
        LOCK_READ = 0,  /**< Acquires the lock in read mode */
        LOCK_WRITE = 8  /**< Acquires the lock in write mode */
    };

	/**
	 * Default constructor, creates a new File that is closed.
	 */
	File();

    /**
     * Creates a new File and opens it.
     *
     * @param[in] filename Path to the file to be opened
     * @param[in] mode Access mode (see @ref EMode)
     *
     * @see Open()
     */
	File(const std::string &filename, EMode mode);

	/**
	 * Destructor.
	 */
	virtual ~File();

	/**
	 * Opens a file in read, write or read/write mode.
	 *
	 * The parameter \a mode can take one of these values:
     * - READ: The file is open in read mode
     * - WRITE: The file is open in write mode
     * - READ_WRITE: The file is open in read/write mode
     * - WRITE_TRUNCATE: The file is open in write mode and its contents are cleared
     *
     * If the file is opened in write or read/write mode but it doesn't exist, it's created.
     *
     * The WRITE_TRUNCATE mode will clear the file contents; however, the other modes always
     * preserve its contents.
     *
	 * @param[in] filename Path to the file to be opened
	 * @param[in] mode Access mode (see @ref EMode)
	 */
	void Open(const std::string &filename, EMode mode);

	/**
     * Closes the file.
     */
	void Close();

	/**
	 * Truncates the file to the specified length.
	 * @param[in] length Length to which the file should be truncated
	 */
	void Truncate(uint length = 0);

    /**
     * Locks the file in read or write mode.
     *
     * The parameter \a opts can take one of these values:
     * - LOCK_READ: The lock is acquired in "read" mode
     * - LOCK_WRITE: The lock is acquired in "write" mode
     *
     * Write and read locks are exclusive, therefore only one kind of lock
     * may be acquired at the same time on the same file.
     *
     * Only a single write lock can be acquired on a file, so acquiring such
     * lock will prevent other processes from acquiring write or read locks
     * on the same file.
     *
     * However, many read locks may be acquired on the file, hence other processes
     * can acquire read locks but not write locks.
     *
     * When trying to acquire a lock on a file, if another process holds a lock
     * that prevents the operation from completing, the locking call will block
     * if \a noblock is false; otherwise, the call will return immediately.
     *
     * @note
     * Locks are not mandatory (i.e. enforced by the underlying operating system),
     * so processes which do not explicitly acquire locks can inadvertedly bypass them.
     *
     * @param[in] opts Type of lock to acquire (see @ref EMode)
     * @param[in] noblock If \p true the call won't block if the lock can't be acquired
     *            and will return immediately
     * @return \p True if the lock could be acquired, \p false otherwise
     */
	bool Lock(EOpts opts, bool noblock = false);

    /**
     * Unlocks a locked file.
     */
	void Unlock();

	/**
	 * Reads data from the file.
	 *
	 * @param[out] buffer Buffer to store read data
     * @param[in] size Number of bytes to read
	 */
	void Read(ByteArray &buffer, uint size = UINT_MAX);

	/**
	 * Reads data from the file.
	 *
     * @param[in] size Number of bytes to read.
	 * @return Buffer containing the read data.
	 */
	ByteArray Read(uint size = UINT_MAX);

    /**
     * Writes data to the file.
     *
     * @param[in] buffer Buffer containing the data to be written
     */
	void Write(const ByteArray &buffer);

	/**
	 * Checks if a file exists.
	 *
	 * @param[in] filename Path to the file to be checked
	 * @return \p True if the file exists, \p false otherwise
	 */
	static bool Exists(const std::string &filename);

	/**
	 * Extracts the path part from the given full path.
	 *
	 * @param[in] fullpath Path + filename of a file
	 * @return Path part of the full path (might be empty)
	 */
	static std::string GetPath(const std::string &fullpath);

    /**
     * Extracts the filename part from the given full path.
     *
     * @param[in] fullpath Path + filename of a file
     * @return Filename part of the full path (might be empty)
     */
    static std::string GetFilename(const std::string &fullpath);

private:
	int m_fd;
};

///@}

#endif // _SMARTLIB_FILE_H_
